#pragma once
#include "../Resource/Mesh/SimpleMesh.hpp"
#include "../Graphics/GeometryHelper.hpp"

namespace zzz{
template<int LEVEL>
class TrackOnSphere
{
public:
  TrackOnSphere()
  {
    for (int i=0; i<LEVEL; i++)
      GeometryHelper::CreateSphere(sphere_[i],i);
  }

  int Track(const Vector3f &dir, vector<int> &tri)
  {
    tri.clear();
    int pos=-1;
    //get first one
    Vector2f bary,bary2;
    for (zuint i=0; i<sphere_[0].faces_.size(); i++)
      if (ptInTri(dir,0,i,bary)) pos=i;

    assert(pos!=-1);
    tri.push_back(pos);

    for (int level=1;level<LEVEL;level++)
    {
      int f0=pos;
      int f1=f0*3+sphere_[level-1].faces_.size();
      int f2=f0*3+1+sphere_[level-1].faces_.size();
      int f3=f0*3+2+sphere_[level-1].faces_.size();
      pos=-1;
      if (ptInTri(dir,level,f0,bary)) {pos=f0;bary2=bary;}
      else if (ptInTri(dir,level,f1,bary)) {pos=f1;bary2=bary;}
      else if (ptInTri(dir,level,f2,bary)) {pos=f2;bary2=bary;}
      else if (ptInTri(dir,level,f3,bary)) {pos=f3;bary2=bary;}
      assert(pos!=-1);
      tri.push_back(pos);
    }

    float uv=Clamp(1.0f-bary[0]-bary[1],0.0f,1.0f);
    if (bary[0]>uv && bary[0]>bary[1]) return sphere_[LEVEL-1].faces_[pos][1];
    else if (bary[1]>bary[0] && bary[1]>uv) return sphere_[LEVEL-1].faces_[pos][2];
    return sphere_[LEVEL-1].faces_[pos][0];
  }

private:
  bool ptInTri(const Vector3f &dir, int level, int face, Vector2f &bary)
  {
    float dist;
    return GeometryHelper::RayInTriangle(\
      sphere_[level].vertices_[sphere_[level].faces_[face][0]],\
      sphere_[level].vertices_[sphere_[level].faces_[face][1]],\
      sphere_[level].vertices_[sphere_[level].faces_[face][2]],\
      Vector3f(0,0,0),dir,dist,bary) && dist>0;

  }

  SimpleMesh sphere_[LEVEL];
};

}